import json
import os
import requests
from typing import Optional
from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi import Form
from starlette.staticfiles import StaticFiles
from pydantic import BaseModel
import asyncio
# from utils.utils import speech_to_text, generate_dialog, text_to_speech, talk_to_huggingface_chat
from models import User, engine, Base,load_qa
from sqlalchemy.orm import sessionmaker
# CORS
from pydantic import BaseModel
from transformers import WhisperProcessor, WhisperForConditionalGeneration,Conversation
from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan
from datasets import load_dataset

import torch
import soundfile as sf
import uuid
from pipes import pipe,chatbot,facebootChat

app = FastAPI()
origins = ["*"]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.mount('/static', StaticFiles(directory='data'), name='static')
app.mount('/file', StaticFiles(directory='file'), name='file')


processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")

embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)

qa = load_qa()
ques = [i['question'] for i in qa]
ans = [i['answer'] for i in qa]


@app.get("/videos")
async def get_videos(path='./data/record'):
    with open(path + "/data.json", mode='r') as f:
        res = json.load(f)
    return {"data": res}


@app.post("/generate_dialog")
async def gen_dialog(req: dict):
    past_user_input = req['past_user_input']
    generated_responses = req['generated_responses']
    text = req['text'] + ". your output can't beyond 30 words!"

    gen = talk_to_huggingface_chat(text)
    return {"data": gen}

    payload = {
        "inputs": {
            "past_user_inputs": past_user_input,
            "generated_responses": generated_responses,
            "text": text
        },
    }
    return {"data": generate_dialog(payload)['generated_text']}


@app.post("/save_audio")
async def save_audio(data=Form(...)):
    bytes = data.file.read()
    with open(f'./data/record/{data.filename}.wav', 'wb') as f:
        f.write(bytes)
    output = speech_to_text(f'./data/record/{data.filename}.wav')

    return {"message": "Success", "data": output}
    out_path = './data/record'
    response = requests.get(url)
    if response.status_code == 200:
        with open(f'{out_path}/{name}.wav', 'wb') as f:
            print(response.content)
            f.write(response.content)
            return {"message": "Success"}
    else:
        print("Failed to download file")
        return {"message": "Failed"}


@app.post("/speech_to_text")
def speech_to_text(data=Form(...)):
    bytes = data.file.read()
    with open(f'./save_record/{data.filename}.wav','wb') as f :
        f.write(bytes)
    try:
        text = pipe(f'./save_record/{data.filename}.wav')['text']
        return {"code":200,"text":text}
    except Exception as e:
        print(e)
        return {"code":500,"error":e}


class Text(BaseModel):
    text:str
@app.post("/text_to_speech")
async def text_to_speech(textModel:Text):
    try:
        inputs = processor(text=textModel.text,return_tensors="pt")
        speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)
        uid = uuid.uuid4().hex
        sf.write(f"file/{uid}.wav", speech.numpy(), samplerate=16000)
        return {"code":200,"file":uid}
    except Exception as e:
        return {"code":500,"error":e}
    

class Conv(BaseModel):
    text:str
    past_user_input:list|None
    generated_responses:list|None
    pattern:str|None

from fuzzywuzzy import fuzz,process

@app.post("/chat")
def chat_to_bot(chat:Conv):
    if chat.pattern == 'qa':
        out = process.extract(chat.text,ques,limit=1)
        if out[0][1] >= 95:
            idx = ques.index(out[0][0])
            return {"code":200,"data":ans[idx]}

    response = {"code":200,"data":None}
    conversation = Conversation(text=chat.text,past_user_inputs=chat.past_user_input,generated_responses=chat.generated_responses)
    conversation = facebootChat(conversation)
    res = conversation.generated_responses[-1]
    response["data"] = res
    return response


async def text_to_speech_controller(req: dict):
    text = req['text']
    payload = {"inputs": text}
    uid = text_to_speech(payload)
    return {"message": "Success", "data": uid} 


class UserModel(BaseModel):
    uid: str | None
    username:  str|None
    password:str|None
    email:str|None
    tel:str |None




@app.post("/register")
async def register(req: UserModel):
    try:
        response = {"code":200, "message": "Success", "data": None}
        uid = req.uid
        name = req.username
        password = req.password
        email = req.email
        tel = req.tel
        # 创建数据库连接
        session = sessionmaker(bind=engine)
        # 创建Session类实例
        s = session()
        # 创建User对象
        user = User( username=name, password=password, email=email, tel=tel)
        # 添加到session:
        s.add(user)
        # 提交即保存到数据库:
        s.commit()
        # 关闭session:
        s.close()

        return response
    except Exception as e:
        print(e)
        response['code'] = 500
        response['message'] = "Failed"
        return response
    


@app.post("/login")
async def login(req:dict):
    username = req['username']
    password = req['password']
    response = {"code": 200, "message": "Success", "data": None}
    # 创建数据库连接
    session = sessionmaker(bind=engine)
    # 创建Session类实例
    s = session()
    # 创建User对象
    user = s.query(User).filter(User.username == username).first()
    if user is None or user.password != password:
        response['code'] = 401
        response['message'] = "Username or password is wrong"
    else:
        response['data'] = user
    # 关闭session:
    s.close()
    return response


@app.get("/get_audio_text")
async def get_audio_text():
    response = {"code": 200, "message": "Success", "data": None}
    files = os.listdir('../audio_test')
    response['data'] = files
    return response

@app.get("/get_read_text/{filename}")
async def get_audio_text(filename:str):
    response = {"code": 200, "message": "Success", "data": None}
    d = []
    with open(f'../audio_test/{filename}', 'r') as f:
        lines = f.readlines()
        for line in lines:
            space = line.find(' ')
            d.append({"text":line[:space].strip(),"pron":line[space+1:].strip()})
    response['data'] = d
    return response


APPID = "ccf4321c"
APIKey = "3ec5b91ea42617578a40cd20918e80c5"
APISecret = "NTFmOWZmYTMzNjRkYzcyMmMyZDI5MTM0"
from utils.utils import initial_and_send,parse_xml

@app.post("/judge_pron")
async def judge_pron(audio=Form(...),words=Form(...)):
    print(words)
    words = words.split(',')
    uid = uuid.uuid4().hex
    with open(f'./score/audio/{uid}.wav','wb') as f:
        f.write(audio.file.read())
    with open(f'./score/word/{uid}.txt','w') as f:
        f.write('[word]\n')
        for word in words:
            f.write(word+'\n')
    initial_and_send(APPID,APIKey,APISecret,AudioFile=f'./score/audio/{uid}.wav',Text=f'./score/word/{uid}.txt',filename=uid)
    # while True:
    #     if os.path.exists(f'./score/score/{uid}.xml'):
    #         break
    # await asyncio.sleep(10)
    with open(f'./score/score/{uid}.xml','r') as f:
        content = f.readlines()
        if len(content) ==0 :
            return {"code":500,"error":"error"}
        content = ''.join(content[1:])
        out = parse_xml(content)
    return {"code":200,"data":out}
    # return {"code":200,"data":[        {
    #         "content": "your",
    #         "total_score": "1.883492"
    #     },
    #     {
    #         "content": "daughter",
    #         "total_score": "4.081366"
    #     },
    #     {
    #         "content": "tall",
    #         "total_score": "4.276588"
    #     },
    #     {
    #         "content": "horse",
    #         "total_score": "4.533162"
    #     }]}



    
